using FluffyUnderware.Curvy.Generator;
using FluffyUnderware.DevTools;
using System;
using UnityEngine;

namespace FluffyUnderware.Curvy.Controllers
{
	[AddComponentMenu("Curvy/Controller/CG Path Controller", 7)]
	[HelpURL("https://curvyeditor.com/doclink/pathcontroller")]
	public class PathController : CurvyController
	{
		[Section("General", true, false, 100, Sort = 0)]
		[SerializeField]
		[CGDataReferenceSelector(typeof(CGPath), Label = "Path/Slot")]
		private CGDataReference m_Path = new CGDataReference();

		public CGDataReference Path
		{
			get
			{
				return m_Path;
			}
			set
			{
				m_Path = value;
			}
		}

		public CGPath PathData => (!Path.HasValue) ? null : Path.GetData<CGPath>();

		public override float Length => (PathData == null) ? 0f : PathData.Length;

		public override bool IsReady => Path != null && !Path.IsEmpty && Path.HasValue;

		protected override float RelativeToAbsolute(float relativeDistance)
		{
			return (PathData == null) ? 0f : PathData.FToDistance(relativeDistance);
		}

		protected override float AbsoluteToRelative(float worldUnitDistance)
		{
			return (PathData == null) ? 0f : PathData.DistanceToF(worldUnitDistance);
		}

		protected override Vector3 GetInterpolatedSourcePosition(float tf)
		{
			return Path.Module.Generator.transform.TransformPoint(PathData.InterpolatePosition(tf));
		}

		protected override void GetInterpolatedSourcePosition(float tf, out Vector3 interpolatedPosition, out Vector3 tangent, out Vector3 up)
		{
			PathData.Interpolate(tf, out interpolatedPosition, out tangent, out up);
			Transform transform = Path.Module.Generator.transform;
			interpolatedPosition = transform.TransformPoint(interpolatedPosition);
			tangent = transform.TransformDirection(tangent);
			up = transform.TransformDirection(up);
		}

		protected override Vector3 GetTangent(float tf)
		{
			return Path.Module.Generator.transform.TransformDirection(PathData.InterpolateDirection(tf));
		}

		protected override Vector3 GetOrientation(float tf)
		{
			return Path.Module.Generator.transform.TransformDirection(PathData.InterpolateUp(tf));
		}

		protected override void Advance(float speed, float deltaTime)
		{
			float tf = base.RelativePosition;
			MovementDirection curyDirection = base.MovementDirection;
			SimulateAdvance(ref tf, ref curyDirection, speed, deltaTime);
			base.MovementDirection = curyDirection;
			base.RelativePosition = tf;
		}

		protected override void SimulateAdvance(ref float tf, ref MovementDirection curyDirection, float speed, float deltaTime)
		{
			int direction = curyDirection.ToInt();
			switch (base.MoveMode)
			{
			case MoveModeEnum.Relative:
				PathData.Move(ref tf, ref direction, speed * deltaTime, base.Clamping);
				break;
			case MoveModeEnum.AbsolutePrecise:
				PathData.MoveBy(ref tf, ref direction, speed * deltaTime, base.Clamping);
				break;
			default:
				throw new NotSupportedException();
			}
			curyDirection = MovementDirectionMethods.FromInt(direction);
		}
	}
}
